#include "include.h"

void bt_aec_process(u8 *ptr, u32 samples, int ch_mode);
void bt_sco_process(u8 *ptr, u32 samples, int ch_mode);
void iis2bt_sco_process(u8 *ptr, u32 samples, int ch_mode);
void bt_alc_process(u8 *ptr, u32 samples, int ch_mode);
void aux_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
void speaker_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
void usbmic_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
void karaok_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
void speex_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
void usb_adc_ext(u8 *ptr, u32 samples, int ch_mode);
bool sco_is_msbc_on(void);
void mic_bt_rec_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
#if FUNC_AUX_EN
    #define aux_sdadc_callback      aux_sdadc_process
#else
    #define aux_sdadc_callback      sdadc_dummy
#endif // FUNC_AUX_EN

#if FUNC_SPEAKER_EN
    #define speaker_sdadc_callback  speaker_sdadc_process
#else
    #define speaker_sdadc_callback  sdadc_dummy
#endif // FUNC_SPEAKER_EN

#if UDE_MIC_TO_DAC
    #define usbmic_sdadc_callback   usb_adc_ext
#elif UDE_MIC_EN
    #define usbmic_sdadc_callback   usbmic_sdadc_process
#else
    #define usbmic_sdadc_callback   sdadc_dummy
#endif

//void lc_sco_set_hci_rx(u16 *ptr, u32 samples);  //通话上传给手机数据接口,常用于对接IIS DSP降噪MIC  //bt_aec_process,bt_alc_process,bt_sco_process在内部均是调用这个函数
#if (DMA_OUT_I2S_SEL == I2S_DMA_BT && I2S_EN) || IIS_RX_2_SCO_SRC
    #define bt_sdadc_callback    iis2bt_sco_process
#else
#if BT_AEC_EN
    #define bt_sdadc_callback    bt_aec_process
#elif BT_ALC_EN
    #define bt_sdadc_callback    bt_alc_process
#else
    #define bt_sdadc_callback    bt_sco_process
#endif //BT_AEC_EN
#endif // DMA_OUT_I2S_SEL
#if SYS_KARAOK_EN
    #define karaok_sdadc_callback   karaok_sdadc_process
#else
    #define karaok_sdadc_callback   sdadc_dummy
#endif

#if !FMRX_INSIDE_EN
    #define fmrx_sdadc_callback     fmrx_sdadc_process
#else
    #define fmrx_sdadc_callback     sdadc_dummy
#endif

#if BT_SPEEX_EN
    #define speex_sdadc_callback     speex_sdadc_process
#else
    #define speex_sdadc_callback     sdadc_dummy
#endif

#if BT_AUX_MIC_MIX_EN
#define AUBUF1DATA      SFR_RW (SFR1_BASE + 0x06*4)
#define AUBUF1CON       SFR_RW (SFR1_BASE + 0x07*4)
#define AUBUF1STARTADDR SFR_RW (SFR1_BASE + 0x08*4)
#define AUBUF1SIZE      SFR_RW (SFR1_BASE + 0x09*4)
#define AUBUF1FIFOCNT   SFR_RW (SFR1_BASE + 0x0a*4)

AT(.com_text.debugstr)
const char str_kinfo[] = "[%d, %d]";

u8 l_vol_num = 5, r_vol_num = 5;
extern const u16 simple_karaok_dvol_table_16[16 + 1];

AT(.text.func.bt)
void printf_vol(void)
{
    static u32 ticks = 0;
    if (tick_check_expire(ticks,1000)) {
        ticks = tick_get();
        printf("--------------->\nDACVOLCON = 0x%X , AUANGCON3 = 0x%X,\n", DACVOLCON&0x7FFF,AUANGCON3&0x7F);
        printf("SRC0VOLCON = 0x%X, SRC1VOLCON = 0x%X\n",SRC0VOLCON&0x7FFF,SRC1VOLCON&0x7FFF);
        printf("AU0LMIXCOEF = 0x%X, AU0RMIXCOEF = 0x%X\n",AU0LMIXCOEF,AU0RMIXCOEF);
        printf("AU1LMIXCOEF = 0x%X, AU1RMIXCOEF = 0x%X\n",AU1LMIXCOEF,AU1RMIXCOEF);
        printf("DACDIGCON0 & (BIT(7)|BIT(8)) = 0x%X\n\n",DACDIGCON0 & (BIT(7)|BIT(8)));
    }
}

AT(.com_text.sdadc)
void karaok_sdadc_process_ext(u8 *ptr, u32 samples, int ch_mode)
{
    int i;
    u32 *ptr32 = (u32*)ptr;
    s16* ppcm = (s16*)ptr;

    //printf_vol();
    if (ch_mode) {
        for (i = 0; i < (samples << ch_mode); i += 2) {
            ppcm[i] = simple_pcm_gain_calc(ppcm[i], simple_karaok_dvol_table_16[l_vol_num]);
            ppcm[i + 1] = simple_pcm_gain_calc(ppcm[i + 1], simple_karaok_dvol_table_16[r_vol_num]);
        }
    }

    for (int i = 0; i < samples; i++) {
        if ((AUBUF1CON & BIT(8)) == 0) {
            AUBUF1DATA = ptr32[i];
        }
    }
}
#else
AT(.com_text.sdadc)
void karaok_sdadc_process_ext(u8 *ptr, u32 samples, int ch_mode){}
#endif // BT_AUX_MIC_MIX_EN

//AUX analog gain: 000(-6DB), 001(-3DB), 010(0DB), 011(+3DB), 100(+6DB), 默认值010(0DB)
//MIC analog gain: 0~23(共24级), step 3DB (-6db ~ +63db)
//adadc digital gain: 0~31, step 3/32 DB, 0~3DB的细调, 保存在gain的低5bit
const sdadc_cfg_t rec_cfg_tbl[] = {
/*   通道,              采样率,     增益,        通路控制,     保留,   样点数,   回调函数*/
    {AUX_CHANNEL_CFG,   SPR_44100,  (2 << 5),    ADC2DAC_EN,     0,      256,    aux_sdadc_callback},            /* AUX     */
    {FMRX_CHANNEL_CFG,  SPR_44100,  (2 << 5),    ADC2DAC_EN,     0,      256,    fmrx_sdadc_callback},           /* FM      */
    {MIC_CHANNEL_CFG,   SPR_16000,  (14 << 5),   ADC2DAC_EN,     0,      240,    speaker_sdadc_callback},        /* SPEAKER */
    {MIC_CHANNEL_CFG,   SPR_8000,   (14 << 5),   ADC2DAC_EN,     0,      128,    bt_sdadc_callback},             /* BTMIC   */
#if UDE_MIC_STEREO
    {UDE_MIC_STEREO_CH, SPR_48000,  (14 << 5),   ADC2DAC_EN,     1,      128,    usbmic_sdadc_callback},         /* USBMIC stereo channel */
#else
    {MIC_CHANNEL_CFG,   SPR_48000,  (14 << 5),   ADC2DAC_EN,     1,      128,    usbmic_sdadc_callback},         /* USBMIC single channel */
#endif // UDE_MIC_STEREO
    {MIC_CHANNEL_CFG,   SPR_44100,  (14 << 5),   ADC2SRC_EN,     0,      256,    karaok_sdadc_callback},         /* KARAOK  */
    {MIC_CHANNEL_CFG,   SPR_8000,   (14 << 5),   ADC2DAC_EN,     0,      160,    speex_sdadc_callback},          /* SPEEX  */
    {MIC_CHANNEL_CFG,   SPR_44100,  (14 << 5),   ADC2SRC_EN,     0,      256,    karaok_sdadc_process_ext},      /* SIMPLE KARAOK  */
#if MIC_AND_BT_REC_EN
    {MIC_CHANNEL_CFG,   SPR_44100,  (14 << 5),   ADC2SRC_EN,     0,      256,    mic_bt_rec_sdadc_process}
#endif
};

const u8 btmic_ch_tbl[] = {CH_MICL0, CH_MICL1, CH_MICR0, CH_MICR1};
const u16 audio_spr_table[] = {48000,44100,38000,32000,24000,22050,16000,12000,11025,8000};

#if REC_STOP_AUSAMPLE
bool rec_stop_ausample_en(void){
    return false;
}
#endif

void audio_path_init(u8 path_idx)
{
    sdadc_cfg_t cfg;
    memcpy(&cfg, &rec_cfg_tbl[path_idx], sizeof(sdadc_cfg_t));

#if FUNC_AUX_EN
    if (path_idx == AUDIO_PATH_AUX) {
        cfg.channel = (xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel;
        cfg.gain = ((u16)xcfg_cb.aux_anl_gain << 5) | xcfg_cb.aux_dig_gain;
    }
#endif // FUNC_AUX_EN

#if FUNC_FMRX_EN
    if (path_idx == AUDIO_PATH_FM) {
        cfg.gain = ((u16)FMRX_AUX_ANL_GAIN << 5);
    }
#endif // FUNC_FMRX_EN

    if (path_idx == AUDIO_PATH_BTMIC || path_idx == AUDIO_PATH_KARAOK) {
        if (path_idx == AUDIO_PATH_BTMIC) {
            if (sys_cb.hfp_karaok_en) {
                memcpy(&cfg, &rec_cfg_tbl[AUDIO_PATH_KARAOK], sizeof(sdadc_cfg_t));
                cfg.sample_rate = SPR_48000;
            } else {
        #if BT_AEC_EN || BT_ALC_EN
        #if (DMA_OUT_I2S_SEL == I2S_DMA_BT && I2S_EN) || IIS_RX_2_SCO_SRC
                cfg.callback = iis2bt_sco_process;
        #else
                if (xcfg_cb.bt_aec_en) {
                    cfg.callback = bt_aec_process;
                } else if (xcfg_cb.bt_alc_en) {
                    cfg.callback = bt_alc_process;
                } else {
                    cfg.callback = bt_sco_process;
                }
        #endif // DMA_OUT_I2S_SEL
        #endif
            }
        }
        #if DUAL_MIC_CHANNEL_EN
        cfg.channel = CH_MICL0|CH_MICR0;
        #else
        cfg.channel = btmic_ch_tbl[xcfg_cb.bt_ch_mic];
        #endif
#if BT_SCO_DBG_EN
        cfg.gain = ((u16)f_bt.mic_anl_gain << 5) | f_bt.mic_dig_gain;
#else
        cfg.gain = ((u16)BT_ANL_GAIN << 5) | BT_DIG_GAIN;
#endif

#if  KARAOK_SEL_DUAL_AUX
        if (path_idx == AUDIO_PATH_KARAOK) {
            cfg.channel = (xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel;
            cfg.gain = ((u16)xcfg_cb.aux_anl_gain << 5) | xcfg_cb.aux_dig_gain;
        }
#endif  //KARAOK_SEL_DUAL_AUX

#if SYS_REVERB_EN
        cfg.sample_rate = SPR_16000;    //只支持16k采样率
#endif // SYS_REVERB_EN
    }

#if AUX_MIC_TWO_CHANNLE
    cfg.channel = CH_AUXL_PF0|CH_AUXR_PF1;
    cfg.sample_rate = SPR_48000;
#endif
#if BT_HFP_MSBC_EN
    if (path_idx == AUDIO_PATH_BTMIC) {
        if (sco_is_msbc_on()) {     //如果开了msbc，则采样率设为16k
            cfg.sample_rate = SPR_16000;
        }
    }

#endif
#if UDE_MIC_KARAOK_EN
    cfg.sample_rate = SPR_48000;
#endif

#if KARAOK_REC_EN
    if(path_idx == AUDIO_PATH_KARAOK && (func_cb.sta == FUNC_SPDIF || func_cb.sta == FUNC_HDMI)){
        cfg.sample_rate = dac_spr_get();
    }
#endif // SPF_REC_EN
    printf("cfg sadc sample_rate: %d\n",audio_spr_table[cfg.sample_rate]);
    sdadc_init(&cfg);
#if 0
    SDADCDIGCON  &= ~(BIT(1) | BIT(9));   //去掉ADC的直流Filter
#endif
    //printf("SDADCDIGCON %08x\n", SDADCDIGCON);
    //printf("SDADCDMACON %08x\n", SDADCDMACON);
    //printf("SDADCGAINCON: %08x\n", SDADCGAINCON);
}

void audio_path_start(u8 path_idx)
{
    sdadc_cfg_t cfg;
    memcpy(&cfg, &rec_cfg_tbl[path_idx], sizeof(sdadc_cfg_t));
#if FUNC_AUX_EN
    if (path_idx == AUDIO_PATH_AUX) {
        cfg.channel = (xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel;
    }
#endif // FUNC_AUX_EN

    if (path_idx == AUDIO_PATH_BTMIC || path_idx == AUDIO_PATH_KARAOK) {
        #if DUAL_MIC_CHANNEL_EN
        cfg.channel = CH_MICL0|CH_MICR0;
        #else
        cfg.channel = btmic_ch_tbl[xcfg_cb.bt_ch_mic];
        #endif
#if KARAOK_SEL_DUAL_AUX
        if (path_idx == AUDIO_PATH_KARAOK) {
            cfg.channel = (xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel;
        }
#endif  //KARAOK_SEL_DUAL_AUX
    }

#if MICL_MUX_DETECT_LINEIN
    if (((cfg.channel & CHANNEL_L) == CH_MICL0) && (is_linein_det_mux_micl())) {
        sys_cb.micl_en = 1;
        micl2gnd_flag = 0;
        GPIOFDIR |= BIT(2);
        GPIOFDE &= ~BIT(2);
        GPIOFPU &= ~BIT(2);
    }
#endif // MICL_MUX_DETECT_LINEIN

#if AUX_MIC_TWO_CHANNLE
    cfg.channel = CH_AUXL_PF0|CH_AUXR_PF1;
#endif

#if SYS_KARAOK_EN
    if (path_idx == AUDIO_PATH_KARAOK) {
        if ((cfg.channel & CHANNEL_L) && (cfg.channel & CHANNEL_R)) {

        }else{
            if(cfg.channel){
                dac_src1_set_ch_mix(0,0,1);
            }
        }
    }
#endif

    sdadc_start(cfg.channel);
}

void audio_path_exit(u8 path_idx)
{
    sdadc_cfg_t cfg;
    memcpy(&cfg, &rec_cfg_tbl[path_idx], sizeof(sdadc_cfg_t));

#if FUNC_AUX_EN
    if (path_idx == AUDIO_PATH_AUX) {
        cfg.channel = (xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel;
    }
#endif // FUNC_AUX_EN

    if (path_idx == AUDIO_PATH_BTMIC || path_idx == AUDIO_PATH_KARAOK) {
        #if DUAL_MIC_CHANNEL_EN
        cfg.channel = CH_MICL0|CH_MICR0;
        #else
        cfg.channel = btmic_ch_tbl[xcfg_cb.bt_ch_mic];
        #endif
    }

#if AUX_MIC_TWO_CHANNLE
     cfg.channel = CH_AUXL_PF0|CH_AUXR_PF1;
#endif

#if  KARAOK_SEL_DUAL_AUX
    if (path_idx == AUDIO_PATH_KARAOK) {
        cfg.channel = (xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel;
        cfg.gain = ((u16)xcfg_cb.aux_anl_gain << 5) | xcfg_cb.aux_dig_gain;
    }
#endif  //KARAOK_SEL_DUAL_AUX

    sdadc_exit(cfg.channel);

#if MICL_MUX_DETECT_LINEIN
    if (((cfg.channel & CHANNEL_L) == CH_MICL0) && (is_linein_det_mux_micl())) {
        GPIOFDIR |= BIT(2);
        GPIOFDE |= BIT(2);
        GPIOFPU |= BIT(2);
        delay_us(10);
        sys_cb.micl_en = 0;
        micl2gnd_flag = 0;
    }
#endif // MICL_MUX_DETECT_LINEIN

    adpll_spr_set(DAC_OUT_SPR);
}

u8 get_aux_channel_cfg(void)
{
#if FUNC_AUX_EN
    //return rec_cfg_tbl[AUDIO_PATH_AUX].channel;
    return ((xcfg_cb.auxr_sel << 4) | xcfg_cb.auxl_sel);    //工具配置AUX通路
#else
    return 0;
#endif // FUNC_AUX_EN
}


//-------------------------------------------------------------------------------------------------
//硬件消人声道,简单地用左声道 - 右声道来实现
//void dac_hw_rm_voice(bool en)
//{
//    AU0LMIXCOEF = 0x80007fff;   //L = L - R
//    AU0RMIXCOEF = 0x80007fff;   //R = L - R
//    if (en) {
//        DACDIGCON0 |= BIT(7);   //EN
//    } else {
//        DACDIGCON0 &= ~BIT(7);  //DIS
//    }
//}

//如果左右声道一样或接近,左右相减这种消人声方式就不合适了，此时需要更复杂的软件消人声来处理.
//软件消人声可以通过库中提供以下数据流接口实现: void dac_sw_rm_voice(s16 *ldata, s16 *rdata);
//使用软件消人声算法时,需要调用先karaok_set_voice_rm_type(1, rm_voice_filter_coef),用于初始化滤波器参数rm_voice_filter_coef。
//使用软软消人声时,需要关硬件消人声，即DACDIGCON0 &= ~BIT(7);
//volatile bool ext_rm_voice_en = false;
//-------------------------------------------------------------------------------------------------

